package com.terrapages.wmsc4j.layer.resolution;

import java.util.Collection;
import java.util.SortedSet;
import java.util.TreeSet;



/**
 * This class is a Set of Resolutions includes index methods so that you can get resolutions
 * based on there zooms. ResolutionSet is a {@link SortedSet} ({@link TreeSet}) starting with the highest resolution (index/zoom = 0)
 * down to the lowest resolution (index/zoom = size()-1).
 * 
 * @author mvivian
 * @date 21 May 2007
 */
public class ResolutionSet extends TreeSet<Resolution>
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Makes an empty set of Resolutions
	 */
	public ResolutionSet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * Makes a ResolutionSet given a Collection
	 * @param c
	 */
	public ResolutionSet(Collection<? extends Resolution> c) {
		super(c);
		// TODO Auto-generated constructor stub
	}

	/**
	 * Makes a ResolutionSet given a SortedSet
	 * @param s
	 */
	public ResolutionSet(SortedSet<Resolution> s) {
		super(s);
		// TODO Auto-generated constructor stub
	}
	
	/**
	 * Creates a populated set of Resolutions starting at the given highest resolution and 
	 * working down dividing by 2 each time until there are the given number of resolutions
	 * 
	 * @param highestResolution The highest resolution at which to start to create all the smaller resolutions
	 * @param numOfResolutions The number of resolutions to populate this set with.
	 */
	public ResolutionSet(final Resolution highestResolution, final int numOfResolutions)
	{
		for (int i = 0; i < numOfResolutions; ++i)
		{
			this.add(new Resolution(highestResolution.getValue() / Math.pow(2, i)));
		}
	}
	


	/**
	 * Returns the highest resolution. Same as first(). 
	 * It just makes code easier to understand.
	 * 
	 * @return the highest resolution in the set.
	 */
	public Resolution getHighestResolution()
	{
		return this.first();
	}
	
	/**
	 * Returns the lowest resolution. Same as last(). 
	 * It just makes code easier to understand.
	 * 
	 * @return the lowest resolution in the set.
	 */
	public Resolution getLowestResolution()
	{
		return this.last();
	}
	
	/**
	 * Returns the resolution at the given index.
	 * The index is not-exactly the same as the tilecache zoom.
	 * Highest resolution = index = 0
	 * Lowest resolution = index = size() -1
	 * 
	 * @param index
	 * @return
	 */
	public Resolution elementAt(int index)
	{
		return this.toArray(new Resolution[this.size()])[index];
	}
	
	/**
	 * returns the index of the Resolution which is closest to the given resolution.
	 * 
	 * @param resolution The Method will find the closest resolution to this one and return its index
	 * @return The index of the Resolution which is the closest to the given resolution
	 */
	public final int getIndex(final Resolution resolution)
	{
		int min = 0;
		int max = this.size()-1;
		int index=min;
		
		Resolution[] resolutions = this.toArray(new Resolution[this.size()]);
		
		while(max - min > 1)
		{
			index = (min + max) / 2;
			final Resolution currentResolution = resolutions[index];
			if(currentResolution.getValue() > resolution.getValue())
			{
				min = index;
			}
			else if (currentResolution.getValue() == resolution.getValue())
			{
				min = max = index;
			}
			else
			{
				max = index;
			}
		}
		
		if(resolutions[min].getValue()-resolution.getValue() < resolution.getValue() - resolutions[max].getValue())
		{
			index = min;
		}
		else
		{
			index= max;
		}
		
		return index;
	}
}
